package client

import (
	"crypto"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/spf13/cast"
	"io/ioutil"
	"longmen/server/config/global"
	"longmen/server/pkg/common/api_models"
	"longmen/server/pkg/common/helper/const"
	"longmen/server/pkg/common/helper/encrypt"
	time2 "longmen/server/pkg/common/helper/timehelper"
	"longmen/server/pkg/db/mysql/models/models_main"
	pb "longmen/server/pkg/protobuf"
	"net/http"
	"net/url"
	"strings"
	"time"
)

const (
	// 慧收钱
	HSQ_METHOD_SWEPTN    = "POLYMERIZE_MAIN_SWEPTN"     //请求的方法名称  扫码支付
	HSQ_METHOD_CASHIER   = "POLYMERIZE_PROGRAM_CASHIER" //服务端返回支付参数，据返回的参数唤醒微信、支付宝客户端，消费者完成支付 调起支付宝与微信
	HSQ_VERSION          = "1.0"                        //版本号
	HSQ_FORMAT           = "JSON"                       //请求头格式
	HSQ_SIGNTYPE         = "RSA2"                       //加密方式
	HSQ_SKEWING_DURATION = 1800                         //30分钟支付有效
	PRIVATEKEY_FILE      = "./hsq_pri.pfx"
)

const (
	PAYMENT_HSP_INIT       = "INIT"       //	慧收钱初始化
	PAYMENT_HSP_PROCESSING = "PROCESSING" //慧收钱处理中
	PAYMENT_HSP_SUCCESS    = "SUCCESS"    //慧收钱成功
	PAYMENT_HSP_FAIL       = "FAIL"       //慧收钱失败
)
const CONTENT_TYPE = "application/x-www-form-urlencoded;charset=utf-8" //请求头
/**
 * @Author admin
 * @Description //基本参数
 * @version: v1.8.0
 * @Date 9:50 2022/8/19
 * @Param
 * @return
 **/
func basicParam(hsqBusinessReq *api_models.HsqBusinessReq) map[string]string {

	headPara := make(map[string]string)
	headPara["method"] = HSQ_METHOD_SWEPTN
	// 请求方法|| hsqBusinessReq.PayType == util.HSQ_NATIVE_WECHAT
	/*	if hsqBusinessReq.Terminal == util.TERMINAL_PC {
			headPara["method"] = HSQ_METHOD_SWEPTN
		} else {
			headPara["method"] = HSQ_METHOD_CASHIER
		}*/

	// 版本
	headPara["version"] = HSQ_VERSION
	// 请求格式
	headPara["format"] = HSQ_FORMAT
	//商户号
	headPara["merchantNo"] = hsqBusinessReq.MerchantNo
	//加密方式
	headPara["signType"] = HSQ_SIGNTYPE
	//加密数据
	headPara["signContent"] = hsqBusinessReq.SignContent
	//签名数据
	headPara["sign"] = _const.EMPTY_STR

	return headPara
}

/**
 * @Author admin
 * @Description //业务请求参数
 * @version: v1.8.0
 * @Date 10:18 2022/8/19
 * @Param
 * @return
 **/
func businessParam(hsqBusinessReq *api_models.HsqBusinessReq) map[string]string {

	businessPara := make(map[string]string)
	//商户订单号
	businessPara["transNo"] = hsqBusinessReq.TransNo
	//支付类型h
	businessPara["payType"] = hsqBusinessReq.PayType
	//交易金额
	businessPara["orderAmt"] = hsqBusinessReq.OrderAmt
	//商品信息摘要
	businessPara["goodsInfo"] = hsqBusinessReq.GoodsInfo
	//前台跳转地址
	businessPara["pageUrl"] = hsqBusinessReq.PageUrl
	//后台回调地址
	businessPara["returnUrl"] = hsqBusinessReq.ReturnUrl
	//请求时间
	businessPara["requestDate"] = time.Now().Format(time2.TIME_LAYOUT_FORMAT_2)
	//原样返回字段
	businessPara["extend"] = hsqBusinessReq.Extend
	//扩展字段
	businessPara["memo"] = hsqBusinessReq.Memo

	return businessPara
}

/**
 * @Author admin
 * @Description //
 * @version: v1.8.0
 * @Date 11:00 2022/8/19
 * @Param
 * @return
 **/
func memoExtendParam(hsqBusinessReq *api_models.HsqBusinessReq) map[string]string {

	extendParam := make(map[string]string)
	//限制卡类型
	extendParam["paylimit"] = ""
	//extendParam["paylimit"] = hsqBusinessReq.Paylimit
	//交易结束时间
	extendParam["timeExpire"] = time2.DateSkewingSecond(HSQ_SKEWING_DURATION)
	//终端用户IP
	extendParam["spbillCreateIp"] = hsqBusinessReq.SpbillCreateIp
	//经度
	extendParam["longitude"] = "116.397128"
	//纬度
	extendParam["latitude"] = "39.916527"

	if hsqBusinessReq.PayType == _const.HSQ_NATIVE_WECHAT {
		extendParam["appid"] = hsqBusinessReq.AppId
	}
	return extendParam
}

/**
 * @Author admin
 * @Description //TODO
 * @version: v1.8.0
 * @Date 15:06 2022/8/19
 * @Param
 * @return
 **/
func HsqApply(hsqReq *api_models.HsqBusinessReq) (*pb.HsqBusinessResp, error) {
	//fName := PAYMENT_HSQ_CODE
	memoPara := memoExtendParam(hsqReq)
	if marshal, err := json.Marshal(memoPara); err == nil {
		hsqReq.Memo = string(marshal)
	} else {
		return nil, err
	}
	businessPara := businessParam(hsqReq)
	if marshal, err := json.Marshal(businessPara); err == nil {
		hsqReq.SignContent = string(marshal)
	}
	param := basicParam(hsqReq)

	convertStr := convertReqSignStr(param["method"], param["version"], param["format"], param["merchantNo"], param["signType"], param["signContent"], hsqReq.ApiSecret)
	//fmt.Println(convertStr)
	param["sign"] = sign(convertStr, hsqReq.ApiKey, hsqReq.MerchantNo)
	values := url.Values{}
	for key, val := range param {
		values.Add(key, val)
	}
	global.Log.Debug(hsqReq.ApiHost+"?", convertStr)
	//global.Log.Debug(hsqReq.ApiHost+"?", strings.NewReader(values.Encode()))
	response, err := http.Post(hsqReq.ApiHost, CONTENT_TYPE, strings.NewReader(values.Encode()))
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	if respBody, err := ioutil.ReadAll(response.Body); err == nil {
		objMap := &api_models.HsqBasicResp{}
		global.Log.Debug("respBody=>", string(respBody))
		json.Unmarshal(respBody, objMap)
		respSign := resSingStr(objMap, hsqReq.ApiSecret)
		if verify(respSign, objMap.Sign, hsqReq.MerchantNo) {
			retObject := &pb.HsqBusinessResp{}
			json.Unmarshal([]byte(objMap.Result), retObject)
			return retObject, nil
		}
	}
	return nil, errors.New("跳转第三方支付失败")
}

func HsqPayCallBack(hsqReq *pb.HsqBasic, paymentApi *models_main.PaymentApi) (map[string]string, error) {

	//respResSign := base64Decode(hsqReq.Sign, hsqReq.MerchantNo)
	//if len(respResSign) > 0 {
	//hsqReq.SignContent = util.Base64Encode(hsqReq.SignContent)
	respSign := convertReqSignStr(hsqReq.Method, hsqReq.Version, hsqReq.Format, hsqReq.MerchantNo, hsqReq.SignType, hsqReq.SignContent, paymentApi.ApiSecret)
	//respSign = util.Base64Encode(hsqReq.SignContent)
	//respSign = strings.ToUpper(util.Md5Hex(respSign))
	if verify(respSign, hsqReq.Sign, hsqReq.MerchantNo) {
		respMap := make(map[string]string)
		json.Unmarshal([]byte(hsqReq.SignContent), &respMap)
		return respMap, nil
	}

	//}
	return nil, errors.New("解码错误")
}

func resSingStr(objMap *api_models.HsqBasicResp, key string) string {
	var strBuilder strings.Builder
	if objMap.Success {
		strBuilder.WriteString("result=")
		strBuilder.WriteString(objMap.Result)
		strBuilder.WriteString("&success=")
		strBuilder.WriteString(cast.ToString(objMap.Success))
	} else {
		strBuilder.WriteString("errorCode=")
		strBuilder.WriteString(objMap.ErrorCode)
		strBuilder.WriteString("&errorMsg=")
		strBuilder.WriteString(objMap.ErrorMsg)
		strBuilder.WriteString("&success=")
		strBuilder.WriteString(cast.ToString(objMap.Success))
	}
	strBuilder.WriteString("&key=")
	strBuilder.WriteString(key)
	return strBuilder.String()
}

/**
 * @Author admin
 * @Description //转换签名字符串
 * @version: v1.8.0
 * @Date 13:02 2022/8/19
 * @Param
 * @return
 **/
func convertReqSignStr(method, version, format, merchantNo, signType, signContent, key string) string {

	var stringBuilder strings.Builder
	stringBuilder.WriteString("method=")
	stringBuilder.WriteString(method)
	stringBuilder.WriteString("&version=")
	stringBuilder.WriteString(version)
	stringBuilder.WriteString("&format=")
	stringBuilder.WriteString(format)
	stringBuilder.WriteString("&merchantNo=")
	stringBuilder.WriteString(merchantNo)
	stringBuilder.WriteString("&signType=")
	stringBuilder.WriteString(signType)
	stringBuilder.WriteString("&signContent=")
	stringBuilder.WriteString(signContent)
	stringBuilder.WriteString("&key=")
	stringBuilder.WriteString(key)
	return stringBuilder.String()
}

/**
 * @Author admin
 * @Description //加密
 * @version: v1.8.0
 * @Date 16:47 2022/8/19
 * @Param
 * @return
 **/
func sign(signStr, apiSecret, merchantNo string) string {

	_, privateKey := encrypt.ReadFromPfx(getPrivateKeyFile(merchantNo), apiSecret)
	signature, _ := encrypt.Sign(signStr, privateKey, crypto.SHA256)
	//signature := util.RsaSign(signStr, privateKey, crypto.SHA256)
	return signature
}

func base64Decode(sign, merchantNo string) string {
	if publicKey, err := encrypt.ReadPublicKeyFromCrt(getPubKeyFile(merchantNo)); err == nil {
		if encrypt, err := encrypt.RsaEncrypt(sign, publicKey); err == nil {
			if decodeByte, err := base64.StdEncoding.DecodeString(encrypt); err == nil {
				return string(decodeByte)
			}
		}
	}
	return ""
}

/**
 * @Author admin
 * @Description //验签
 * @Date 0:06 2022/8/21
 * @Param
 * @return
 **/
func verify(content, sign, merchantNo string) bool {
	if publicKey, err := encrypt.ReadPublicKeyFromCrt(getPubKeyFile(merchantNo)); err == nil {
		return encrypt.Verify(content, publicKey, sign, crypto.SHA256)
	}
	return false
}

/**
 * @Author admin
 * @Description //私钥文件名称
 * @version: v1.8.0
 * @Date 16:41 2022/8/20
 * @Param
 * @return
 **/
func getPrivateKeyFile(merchantNo string) string {
	return fmt.Sprintf("secret/%s_pri.pfx", merchantNo)
}

/**
 * @Author admin
 * @Description //公钥名称
 * @version: v1.8.0
 * @Date 16:42 2022/8/20
 * @Param
 * @return
 **/
func getPubKeyFile(merchantNo string) string {
	return fmt.Sprintf("secret/MANDAO_%s_pub.cer", merchantNo)
}
